import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.JPanel;

class Chart {
	private Color color = Color.WHITE;

	private ArrayList<Double> data;

	private String dataFormat = "%d";

	/**
	 * Creates empty chart.
	 */
	public Chart() {
		reset();
	}

	/**
	 * Adds new value to the chart.
	 * 
	 * @param value
	 *            value
	 */
	public void addValue(double value) {
		data.add(value);
	}

	/**
	 * Returns chart color (both text and lines).
	 * 
	 * @return
	 */
	public Color getColor() {
		return color;
	}

	/**
	 * Sets chart color (both text and lines).
	 * 
	 * @param color
	 */
	public void setColor(Color color) {
		this.color = color;
	}

	/**
	 * Returns chart data (unmodifiable).
	 * 
	 * @return chart data
	 */
	List<Double> getData() {
		return Collections.unmodifiableList(data);
	}

	/**
	 * Returns data labels format.
	 * 
	 * @return format string
	 */
	public String getDataFormat() {
		return dataFormat;
	}

	private double getMaxValue() {
		double max = 0;

		for (Double d : data) {
			if (d > max) {
				max = d;
			}
		}

		return max;
	}

	int getXScale(int width) {
		return width / (data.size() - 1);
	}

	double getYScale(int height) {
		return (double) height / getMaxValue();
	}

	/**
	 * Clears chart data.
	 */
	public void reset() {
		data = new ArrayList<>();
	}

	/**
	 * Sets data labels format.
	 * 
	 * @param dataFormat
	 *            format string
	 */
	public void setDataFormat(String dataFormat) {
		this.dataFormat = dataFormat;
	}

}

@SuppressWarnings("serial")
public class ExtraSimplePlotter extends JPanel {
	private final static int DEFAULT_X_MARGIN = 25;
	private final static int DEFAULT_Y_MARGIN = 25;
	private static final int ITEM_BOX_SIZE = 2;

	ArrayList<Chart> charts = new ArrayList<>();
	double computedMinXScale;

	double computedMinYScale;
	private String[] labels;

	int xMargin = DEFAULT_X_MARGIN;
	int yMargin = DEFAULT_Y_MARGIN;

	public ExtraSimplePlotter() {
		setSize(500, 500);
	}

	public void addChart() {
		Chart chart = new Chart();
		charts.add(chart);
	}

	private void clearPanel(Graphics g) {
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, getWidth(), getHeight());
	}

	private void computeScale() {
		computedMinXScale = Double.MAX_VALUE;
		computedMinYScale = Double.MAX_VALUE;
		for (Chart chart : charts) {
			if (chart.getXScale(getWidth() - 2 * xMargin) < computedMinXScale) {
				computedMinXScale = chart.getXScale(getWidth() - 2 * xMargin);
			}
			if (chart.getYScale(getHeight() - 2 * yMargin) < computedMinYScale) {
				computedMinYScale = chart.getYScale(getHeight() - 2 * yMargin);
			}
		}
	}

	private void drawAxes(Graphics g) {
		g.setColor(Color.GRAY);
		g.drawLine(DEFAULT_X_MARGIN, DEFAULT_Y_MARGIN, DEFAULT_X_MARGIN,
				getHeight() - DEFAULT_Y_MARGIN);
		g.drawLine(DEFAULT_X_MARGIN, getHeight() - DEFAULT_Y_MARGIN, getWidth()
				- DEFAULT_X_MARGIN, getHeight() - DEFAULT_Y_MARGIN);
	}

	private void drawCenteredText(Graphics g, int x, int y, String text) {
		g.drawString(text,
				(int) (x - g.getFontMetrics().getStringBounds(text, g)
						.getWidth() / 2), y);
	}

	private void drawCharts(Graphics g) {
		for (Chart chart : charts) {
			Integer oldX = null;
			Integer oldY = null;
			for (int i = 0; i < chart.getData().size(); i++) {
				int x = (int) (xMargin + i * computedMinXScale);
				int y = (int) (getHeight() - yMargin - chart.getData().get(i)
						* computedMinYScale);
				if (oldX != null && oldY != null) {
					g.setColor(chart.getColor().darker());
					g.drawLine(x, y, oldX, oldY);
				}
				g.setColor(chart.getColor());
				g.drawRect(x - ITEM_BOX_SIZE, y - ITEM_BOX_SIZE,
						2 * ITEM_BOX_SIZE, 2 * ITEM_BOX_SIZE);
				String strValue = String.format(chart.getDataFormat(), chart
						.getData().get(i).intValue());
				drawCenteredText(g, x, y - 10, strValue);
				oldX = x;
				oldY = y;
			}
		}
	}

	private void drawLabels(Graphics g) {
		int x = DEFAULT_X_MARGIN;
		int y = getHeight() - DEFAULT_Y_MARGIN;
		for (String label : labels) {
			g.setColor(Color.GRAY);
			drawCenteredText(g, x, y + 15, label);
			x += computedMinXScale;
		}
	}

	public Chart getChart(int index) {
		return charts.get(index);
	}

	public int getXMargin() {
		return xMargin;
	}

	public int getYMargin() {
		return yMargin;
	}

	private void initAntialiasing(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
				RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
		g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
				RenderingHints.VALUE_FRACTIONALMETRICS_ON);
	}

	public void paint(Graphics g) {
		initAntialiasing(g);
		clearPanel(g);
		drawAxes(g);
		computeScale();
		drawCharts(g);
		drawLabels(g);
	}

	void setLabels(String[] labels) {
		this.labels = labels.clone();
	}

	public void setXMargin(int xMargin) {
		this.xMargin = xMargin;
	}

	public void setYMargin(int yMargin) {
		this.yMargin = yMargin;
	}
}